#!/usr/bin/python
  
from twisted.conch import error
from twisted.conch.ssh import session, transport, connection, keys, userauth, channel, common
from twisted.internet import defer, protocol, reactor
from twisted.python import log
  
import os, sys, struct, tty, fcntl, base64, signal, stat, errno
  
class CalcifyClientTransport(transport.SSHClientTransport):
  
    def __init__(self, username, calcify_player):
        self.username = username
        self.calcify_player = calcify_player
  
    def verifyHostKey(self, pubKey, fingerprint):
        # @TODO verify that fingerprint matches stored one for this server
        return defer.succeed(True)
  
    def connectionSecure(self):
        self.requestService(
            CalcifyPasswordAuth(
                self.username,
                self.calcify_player,
                CalcifyClientConnection(self.calcify_player)))
  
class CalcifyPasswordAuth(userauth.SSHUserAuthClient):
  
    preferredOrder = ['publicKey']
  
    def __init__(self, username, calcify_player, conn):
        self.calcify_player = calcify_player
        userauth.SSHUserAuthClient.__init__(self, username, conn)
  
    def getPassword(self, prompt=None):
        return None
  
    def getPublicKey(self):
        print "getPublicKey"
        return keys.getPublicKeyString(data=self.calcify_player['public_key'])
  
    def getPrivateKey(self):
        print "getPrivateKey"
        return defer.succeed(
            keys.getPrivateKeyObject(data=self.calcify_player['private_key']))
  
class CalcifyClientConnection(connection.SSHConnection):
  
    def __init__(self, calcify_player, *a, **kw):
        connection.SSHConnection.__init__(self)
        self.calcify_player = calcify_player
  
    def serviceStarted(self):
        self.openChannel(CalcifyChannel(self.calcify_player, conn=self))
  
class CalcifyChannel(channel.SSHChannel):
    name = 'session'
  
    def __init__(self, calcify_player, *a, **kw):
        channel.SSHChannel.__init__(self, *a, **kw)
        self.calcify_player = calcify_player
  
    def channelOpen(self, data):
        print "channelOpen"
        #self.conn.sendRequest(
        #   self, 'exec', common.NS('ls'), wantReply=True).addCallback(
        #   self._gotResponse)
  
        ###
        fd = sys.stdin.fileno()
        term = os.environ['TERM']
        winsz = fcntl.ioctl(fd, tty.TIOCGWINSZ, '12345678')
        winSize = struct.unpack('4H', winsz)
        ptyReqData = session.packRequest_pty_req(term, winSize, '')
        self.conn.sendRequest(self, 'pty-req', ptyReqData)
        #signal.signal(signal.SIGWINCH, self._windowResized)
        ###
  
        self.conn.sendRequest(
            self, 'shell', '', wantReply=True).addCallback(self._gotResponse)
        self.calcify_player.ssh_channel_open(self)
  
    def _gotResponse(self, _):
        print "_gotResponse: %s" % repr(_)
        #self.calcify_player.tell(self.data)
        #self.data = ""
        #self.conn.sendEOF(self)
  
    # self.write is used to send data
    def dataReceived(self, data):
        #print "dataReceived: %s" % repr(data)
        self.calcify_player.direct_write(data)
        #self.data += data
  
    #def closed(self):
    #   reactor.stop()
  
class CalcifyClientFactory(protocol.ClientFactory):
  
    def __init__(self, username, calcify_player):
        self.username = username
        self.calcify_player = calcify_player
  
    def buildProtocol(self, addr):
        protocol = CalcifyClientTransport(self.username, self.calcify_player)
        return protocol
  
if __name__ == "__main__":
    import sys, getpass
    #log.startLogging(sys.stdout, setStdout=0)
    server = sys.argv[1]
    #command = sys.argv[2]
    #username = raw_input("Username: ")
    factory = CalcifyClientFactory('#me', None)
    reactor.connectTCP(server, 22, factory)
    reactor.run()
  